use modular_bitfield_msb::prelude::*;
use super::error::*;

use crate::byte::*;

#[derive(Debug)]
pub struct SeqSectionHeader {
    num_of_seq:u32,
    symbol_compression_modes:SymbolCompressionModes,
}

impl SeqSectionHeader {
    pub fn serialize_into<W:ByteWrite>(&self,writer:&mut ByteWriter<W>) -> SeqResult<()> {
        let num_of_seq = self.num_of_seq;
        if num_of_seq < 128 {
            writer.write_from_u8(num_of_seq as u8)?;
        } else if num_of_seq < 0x7f00 {
            let buf = [
                ((num_of_seq & 0xff00) >> 8) as u8 + 128,
                (num_of_seq & 0xff) as u8
            ];
            writer.write_from_bytes(&buf)?;
        } else {
            let num_of_seq = num_of_seq - 0x7f00;
            let buf = [255,
                (num_of_seq & 0xff) as u8,
                ((num_of_seq & 0xff00) >> 8) as u8,
            ];
            writer.write_from_bytes(&buf)?;
        }
        writer.write_from_u8(self.symbol_compression_modes.into())?;
        Ok(())
    }

    pub fn deserialize_from<R:ByteRead>(total_len:&mut u32,reader:&mut ByteReader<R>) -> SeqResult<Self> {
        let first_byte = reader.read_to_u8()?;
        let num_of_seq= if first_byte < 128 {
            *total_len -= 2;
            first_byte as u32
        } else if first_byte < 255 {
            *total_len -= 3;
            let second_byte = reader.read_to_u8()? as u32;
            ((first_byte as u32 - 128) << 8) + second_byte
        } else {
            *total_len -= 4;
            let second_byte = reader.read_to_u8()? as u32;
            let third_byte = reader.read_to_u8()? as u32;
            second_byte + (third_byte << 8) + 0x7F00
        };
        let symbol_compression_modes = SymbolCompressionModes::from(reader.read_to_u8()?);
        Ok(Self { num_of_seq, symbol_compression_modes })
    }

    pub fn num_of_seq(&self) -> u32 {
        self.num_of_seq
    }

    pub fn symbol_compression_modes(&self) -> SymbolCompressionModes {
        self.symbol_compression_modes
    }

    pub fn literal_lengths_mode(&self) -> CompressionMode {
        self.symbol_compression_modes.literal_lengths_mode()
    }

    pub fn offsets_mode(&self) -> CompressionMode {
        self.symbol_compression_modes.offsets_mode()
    }

    pub fn match_lengths_mode(&self) -> CompressionMode {
        self.symbol_compression_modes.match_lengths_mode()
    }
}

#[bitfield]
#[repr(u8)]
#[derive(Clone, Copy)]
pub struct SymbolCompressionModes {
    pub literal_lengths_mode:CompressionMode,
    pub offsets_mode:CompressionMode,
    pub match_lengths_mode:CompressionMode,
    #[skip] _reversed:B2,
}

impl std::fmt::Debug for SymbolCompressionModes {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let literal_lengths_mode = self.literal_lengths_mode();
        let offsets_mode = self.offsets_mode();
        let match_lengths_mode = self.match_lengths_mode();
        f.debug_struct("BlockHeader")
            .field("literal_lengths_mode", &literal_lengths_mode)
            .field("offsets_mode", &offsets_mode)
            .field("match_lengths_mode", &match_lengths_mode)
            .finish()
    }
}


#[derive(Debug, Clone, Copy, BitfieldSpecifier)]
#[bits = 2]
pub enum CompressionMode {
    PredefinedMode,
    RLEMode,
    FSECompressedMode,
    RepeatMode,
}

impl CompressionMode {
    pub fn value(self) -> u8 {
        match self {
            Self::PredefinedMode => 0,
            Self::RLEMode => 1,
            Self::FSECompressedMode => 2,
            Self::RepeatMode => 3,
        }
    }
}

impl From<u8> for CompressionMode {
    fn from(value: u8) -> Self {
        match value {
            0 => Self::PredefinedMode,
            1 => Self::RLEMode,
            2 => Self::FSECompressedMode,
            3 => Self::RepeatMode,
            _ => panic!("invalid compression mode"),
        }
    }
}